﻿/*--------------------------------------------------------------------------
Copyright (C) 2017  北京中兴通网络科技股份有限公司版权所有。   
功能描述：扫描枪（USB，钩子 ）工作类
创建时间：2017-10-19
创建人员：dingyifang
--------------------------------------------------------------------------*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;

namespace Mosdar_Weld
{
    /// <summary>
    /// 扫描枪（USB，钩子 ）工作类
    /// </summary>
    public class BarCodeHook
    {
        /// <summary>
        /// 扫描枪扫描委托
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public delegate void BardCodeDeletegate(object sender, BarCodesEventArgs e);

        /// <summary>
        /// 扫描枪扫描事件
        /// </summary>
        public event BardCodeDeletegate BarCodeEvent; 

        /// <summary>
        /// 钩子函数返回信息
        /// </summary>
        private struct EventMsg
        {
            public int message;
            public int paramL;
            public int paramH;
            public int Time;
            public int hwnd;
        } 

        /// <summary>
        /// 扫描枪扫描事件参数
        /// </summary>
        BarCodesEventArgs barCode = new BarCodesEventArgs();

        /// <summary>
        /// 键盘钩子标识
        /// </summary>
        int hKeyboardHook = 0;

        /// <summary>
        /// 扫描信息
        /// </summary>
        string strBarCode = "";

        /// <summary>
        /// 键盘输入（扫码枪扫描）钩子
        /// </summary>
        /// <param name="nCode"></param>
        /// <param name="wParam"></param>
        /// <param name="lParam"></param>
        /// <returns></returns>
        private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)
        {
            if (nCode == 0)
            {
                EventMsg msg = (EventMsg)Marshal.PtrToStructure(lParam, typeof(EventMsg));
                if (wParam == 0x100)//WM_KEYDOWN=0x100
                {
                    barCode.VirtKey = msg.message & 0xff;//虚拟吗
                    barCode.ScanCode = msg.paramL & 0xff;//扫描码
                    StringBuilder strKeyName = new StringBuilder(225);
                    if (NativeMethods.GetKeyNameText(barCode.ScanCode * 65536, strKeyName, 255) > 0)
                    {
                        barCode.KeyName = strKeyName.ToString().Trim(new char[] { ' ', '\0' });
                    }
                    else
                    {
                        barCode.KeyName = "";
                    }
                    byte[] kbArray = new byte[256];
                    uint uKey = 0;
                    NativeMethods.GetKeyboardState(kbArray);


                    if (NativeMethods.ToAscii(barCode.VirtKey, barCode.ScanCode, kbArray, ref uKey, 0))
                    {
                        barCode.AscII = uKey;
                        barCode.Chr = Convert.ToChar(uKey);
                    }

                    TimeSpan ts = DateTime.Now.Subtract(barCode.Time);

                    if (ts.TotalMilliseconds > 50)
                    {
                        strBarCode = barCode.Chr.ToString();
                    }
                    else
                    {
                        if ((msg.message & 0xff) == 13 && strBarCode.Length > 3)
                        {
                            barCode.BarCode = strBarCode;
                            barCode.IsValid = true;
                        }
                        strBarCode += barCode.Chr.ToString();
                    }
                    barCode.Time = DateTime.Now;
                    if (BarCodeEvent != null) BarCodeEvent(this, barCode);//触发事件
                    barCode.IsValid = false;
                }
            }
            return (int)NativeMethods.CallNextHookEx(new IntPtr(hKeyboardHook), nCode, new IntPtr(wParam), lParam);
        }

        /// <summary>
        /// 安装钩子
        /// </summary>
        /// <returns></returns> 
        public bool Start()
        {
            if (hKeyboardHook == 0)
            {
                //WH_KEYBOARD_LL=13
                hKeyboardHook = (int)(NativeMethods.SetWindowsHookEx(13, 
                    new NativeMethods.HookProc(KeyboardHookProc), 
                    Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]), 
                    0));
            }
            return (hKeyboardHook != 0);
        }

        /// <summary>
        /// 卸载钩子
        /// </summary>
        /// <returns></returns>
        public bool Stop()
        {
            if (hKeyboardHook != 0)
            {
                return NativeMethods.UnhookWindowsHookEx(hKeyboardHook);
            }
            return true;
        }
    }
}
